package com.tuniu.agents.tools.flights.domestic.roundtrip;

import com.fasterxml.jackson.annotation.JsonClassDescription;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import com.tuniu.agents.advisor.ChatEnvironmentMemory;
import com.tuniu.agents.message.ToolLoggerInfo;
import com.tuniu.agents.tools.flights.FlightProperties;
import com.tuniu.agents.tools.flights.model.FlightBookParam;
import com.tuniu.agents.tools.flights.model.Url;
import com.tuniu.agents.tools.flights.utils.FlightCommonUtils;
import com.tuniu.agents.util.HttpManager;
import com.tuniu.agents.util.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.model.ToolContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;

public class RoundFlightInformationQueryTool implements BiFunction<RoundFlightInformationQueryTool.Request, ToolContext, RoundFlightInformationQueryTool.Response> {

    public static final String TOOLNAME = "RoundFlightInformationQueryTool";

    private static final Logger logger = LoggerFactory.getLogger(RoundFlightInformationQueryTool.class);

    private final String roundFlightInformationQueryToolUrl;

    @Autowired(required = false)
    private ChatEnvironmentMemory chatEnvironmentMemory;

    @Autowired
    private HttpManager httpManager;

    public RoundFlightInformationQueryTool(FlightProperties exampleProperties) {
        this.roundFlightInformationQueryToolUrl = exampleProperties.getRoundFlightInformationQueryToolUrl();
    }

    @ToolLoggerInfo
    @Override
    public Response apply(Request request, ToolContext context) {
        try {
            logger.info("RoundFlightInformationQueryTool request parameters: {} flightApiUrl: {}", request, roundFlightInformationQueryToolUrl);
            Map<String, Object> map = context.getContext();
            Map<String, Object> hashMap = chatEnvironmentMemory.get((String) map.get("conversation_id"));
            Request requestCopy = new Request(request.flightNo(), (String) hashMap.get("queryId"));
            Response post = httpManager.post(roundFlightInformationQueryToolUrl, requestCopy, Response.class);
            return post.buildResponse();
        } catch (Exception e) {
            logger.error("RoundFlightInformationQueryTool request exception: {}", e.getMessage());
            return null;
        }
    }

    @JsonClassDescription("国内机票往返航班详情查询入参")
    public record Request(
            @JsonProperty(value = "flightNo") @JsonPropertyDescription("指定的国内航班号，或多个#号拼接的国际航班号，且所有字母必须大些，例如：MU5296#MU9635") String flightNo,
            @JsonProperty(value = "queryId") @JsonPropertyDescription("列表返回的查询快照ID") String queryId) {
    }

    @JsonClassDescription("国内机票往返航班详情查询返参")
    public record Response(
            @JsonProperty(required = true,
                    value = "successCode") @JsonPropertyDescription("响应码") boolean successCode,
            @JsonProperty(required = true,
                    value = "success") @JsonPropertyDescription("成功标识，成功：\"查询成功！\"，失败：\"查询失败！\"") String success,
            @JsonProperty(required = true,
                    value = "flightInfo") @JsonPropertyDescription("航程信息") List<FlightInfo> flightInfo,
            @JsonProperty(required = true,
                    value = "cabinInfo") @JsonPropertyDescription("舱位信息") List<CabinInfo> cabinInfo) {

        private String convertTimeFormat(String time) {
            if (StringUtils.hasText(time)) {
                return time.replace("m", "分").replace("h", "时");
            }
            return time;
        }

        public Response buildResponse() {
            List<FlightInfo> flightInfos = this.flightInfo.stream().map(flightInfo -> {
                return new FlightInfo(
                        flightInfo.departureAirport,
                        flightInfo.departureTerminal,
                        flightInfo.arrivalAirport,
                        flightInfo.arrivalTerminal,
                        flightInfo.flightNumber,
                        flightInfo.airComImageUrl,
                        flightInfo.craftType,
                        flightInfo.type,
                        flightInfo.stopPoint,
                        convertTimeFormat(flightInfo.stopTime),
                        flightInfo.departureTime,
                        flightInfo.arrivalTime,
                        flightInfo.punctualityRate,
                        convertTimeFormat(flightInfo.totalDuration),
                        flightInfo.planModel,
                        flightInfo.shareFlightNo,
                        flightInfo.mealCode,
                        convertTimeFormat(flightInfo.transferTime),
                        flightInfo.transferPoint,
                        flightInfo.visaTips,
                        flightInfo.hanging,
                        flightInfo.airlineCompany,
                        flightInfo.departureCityName,
                        flightInfo.arrivalCityName
                );
            }).toList();
            return new Response(
                    this.successCode,
                    this.success,
                    flightInfos,
                    this.cabinInfo
            );
        }
    }

    @JsonClassDescription("航程信息")
    public record FlightInfo(
            @JsonProperty(value = "departureAirport") @JsonPropertyDescription("出发机场") String departureAirport,
            @JsonProperty(value = "departureTerminal") @JsonPropertyDescription("出发航站楼") String departureTerminal,
            @JsonProperty(value = "arrivalAirport") @JsonPropertyDescription("到达机场") String arrivalAirport,
            @JsonProperty(value = "arrivalTerminal") @JsonPropertyDescription("到达航站楼") String arrivalTerminal,
            @JsonProperty(value = "flightNumber") @JsonPropertyDescription("航班号") String flightNumber,
            @JsonProperty(value = "airComImageUrl") @JsonPropertyDescription("航司图标url") List<String> airComImageUrl,
            @JsonProperty(value = "craftType") @JsonPropertyDescription("机型") String craftType,
            @JsonProperty(value = "type") @JsonPropertyDescription("航班类型：直飞，中转，联程，经停") String type,
            @JsonProperty(value = "stopPoint") @JsonPropertyDescription("经停城市") String stopPoint,
            @JsonProperty(value = "stopTime") @JsonPropertyDescription("经停时长") String stopTime,
            @JsonProperty(value = "departureTime") @JsonPropertyDescription("出发时间") String departureTime,
            @JsonProperty(value = "arrivalTime") @JsonPropertyDescription("到达时间") String arrivalTime,
            @JsonProperty(value = "punctualityRate") @JsonPropertyDescription("准点率") String punctualityRate,
            @JsonProperty(value = "totalDuration") @JsonPropertyDescription("总时长") String totalDuration,
            @JsonProperty(value = "planModel") @JsonPropertyDescription("机型大小，1 大，2 中，3 小") String planModel,
            @JsonProperty(value = "shareFlightNo") @JsonPropertyDescription("实际承运航班号") String shareFlightNo,
            @JsonProperty(value = "mealCode") @JsonPropertyDescription("餐食") String mealCode,
            @JsonProperty(value = "transferTime") @JsonPropertyDescription("中转时长") String transferTime,
            @JsonProperty(value = "transferPoint") @JsonPropertyDescription("中转城市") String transferPoint,
            @JsonProperty(value = "visaTips") @JsonPropertyDescription("过境签") String visaTips,
            @JsonProperty(value = "hanging") @JsonPropertyDescription("托运行李") String hanging,
            @JsonProperty(value = "airlineCompany") @JsonPropertyDescription("航司") String airlineCompany,
            @JsonProperty(value = "departureCityName") @JsonPropertyDescription("出发城市") String departureCityName,
            @JsonProperty(value = "arrivalCityName") @JsonPropertyDescription("到达城市") String arrivalCityName) {

        public FlightInfo buildFlightInfo(String departureCityName, String arrivalCityName) {
            return new FlightInfo(
                    this.departureAirport, this.departureTerminal, this.arrivalAirport, this.arrivalTerminal, this.flightNumber,
                    this.airComImageUrl, this.craftType, this.type, this.stopPoint, this.stopTime, this.departureTime,
                    this.arrivalTime, this.punctualityRate, this.totalDuration, this.planModel, this.shareFlightNo,
                    this.mealCode,this.transferTime,this.transferPoint,this.visaTips,this.hanging,
                    this.airlineCompany, departureCityName, arrivalCityName
            );

        }
    }

    @JsonClassDescription("舱位信息")
    public record CabinInfo(
            @JsonProperty(value = "priceWithTax") @JsonPropertyDescription("成人含税价格") String priceWithTax,
            @JsonProperty(value = "childPriceWithTax") @JsonPropertyDescription("儿童含税价格") String childPriceWithTax,
            @JsonProperty(value = "infPriceWithTax") @JsonPropertyDescription("婴儿含税价格") String infPriceWithTax,
            @JsonProperty(value = "price") @JsonPropertyDescription("成人票面价格") String price,
            @JsonProperty(value = "childPrice") @JsonPropertyDescription("儿童票面价格") String childPrice,
            @JsonProperty(value = "infPrice") @JsonPropertyDescription("婴儿票面价格") String infPrice,

            @JsonProperty(value = "sourceId") @JsonPropertyDescription("资源ID") String sourceId,
            @JsonProperty(value = "aiCabinInfos") @JsonPropertyDescription("仓位信息") List<AiCabinInfo> aiCabinInfos,
            @JsonProperty(value = "url") @JsonPropertyDescription("跳转链接") Url url) {

        public CabinInfo buildCabinInfo(Url url){
            return new CabinInfo(
                    this.priceWithTax,
                    this.childPriceWithTax,
                    this.infPriceWithTax,
                    this.price,
                    this.childPrice,
                    this.infPrice,
                    this.sourceId,
                    this.aiCabinInfos,
                    url
            );

        }
    }

    @JsonClassDescription("舱位信息")
    public record AiCabinInfo(
            @JsonProperty(value = "buyCondition") @JsonPropertyDescription("购买条件") String buyCondition,
            @JsonProperty(value = "saleControl") @JsonPropertyDescription("销售控制") List<String> saleControl,
            @JsonProperty(value = "refundChangeRule") @JsonPropertyDescription("退改签") String refundChangeRule,
            @JsonProperty(value = "baggageInfo") @JsonPropertyDescription("行李信息") String baggageInfo,
            @JsonProperty(value = "reimbursementProof") @JsonPropertyDescription("报销凭证") String reimbursementProof,
            @JsonProperty(value = "remainingSeats") @JsonPropertyDescription("余位") String remainingSeats,
            @JsonProperty(value = "mealCode") @JsonPropertyDescription("餐食") String mealCode,
            @JsonProperty(value = "cabinClass") @JsonPropertyDescription("舱等") String cabinClass) {
    }

    public static Response buildCard(String flightsJson, Map<String, Object> hashMap) {
        Response response = JsonUtil.fromJson(flightsJson, Response.class);
        if (!response.successCode) {
            return null;
        }
        buildDetailUrl(response, hashMap);
        return response;
    }

    public static void buildDetailUrl(Response result, Map<String, Object> qParams) {
        try {
            List<FlightInfo> flightInfos = result.flightInfo;
            List<CabinInfo> cabinInfos = result.cabinInfo;

            if (CollectionUtils.isEmpty(flightInfos) || CollectionUtils.isEmpty(cabinInfos)) {
                logger.info("RoundFlightInformationQueryTool buildDetailUrl() flightInfos or cabinInfos is empty");
                return;
            }
            flightInfos.set(0,flightInfos.get(0).buildFlightInfo(qParams.get("departureCityName").toString(), qParams.get("arrivalCityName").toString()));
            flightInfos.set(1,flightInfos.get(1).buildFlightInfo(qParams.get("arrivalCityName").toString(), qParams.get("departureCityName").toString()));
            FlightInfo goFlightInfo = flightInfos.get(0);
            FlightInfo backFlightInfo = flightInfos.get(1);
            for (int i = 0; i < cabinInfos.size(); i++) {
                CabinInfo cabinInfo = cabinInfos.get(i);
                if (cabinInfos.get(i) == null) {
                    logger.info("RoundFlightInformationQueryTool buildDetailUrl() Cabin details are empty");
                    continue;
                }
                // Additional processing for cabinInfo can be added here if needed
            }

        } catch (Exception e) {
            logger.info("RoundFlightInformationQueryTool buildDetailUrl() exception: {}", e.getMessage(), e);
        }
    }

    public static String buildMarkdown(Response response){
        StringBuilder markdown = new StringBuilder();
        markdown.append("| 航班号 | 出发时间 | 到达时间 | 出发机场 | 到达机场 | 机型 | 航空公司 | 出发城市 | 到达城市 |\n");
        markdown.append("| --- | --- | --- | --- | --- | --- | --- | --- | --- |\n");

        for (FlightInfo flightInfo : response.flightInfo()) {
            markdown.append("| ").append(flightInfo.flightNumber())
                    .append("| ").append(flightInfo.departureTime())
                    .append("| ").append(flightInfo.arrivalTime())
                    .append("| ").append(flightInfo.departureAirport())
                    .append("机场| ").append(flightInfo.arrivalAirport())
                    .append("机场| ").append(flightInfo.craftType())
                    .append("| ").append(flightInfo.airlineCompany())
                    .append("| ").append(flightInfo.departureCityName())
                    .append("| ").append(flightInfo.arrivalCityName())
                    .append("|\n");
        }
        markdown.append("\n");

        markdown.append("| 成人价格 | 去程航班退改签规则 | 去程航班行李额信息 | 去程航班余位 | 去程航班舱等 | 返程航班退改签规则 | 返程航班行李额信息 | 返程航班余位 | 返程航班舱等 |\n");
        markdown.append("| --- | --- | --- | --- | --- | --- | --- | --- | --- |\n");

        for (CabinInfo cabinInfo : response.cabinInfo) {
            AiCabinInfo goCabinInfo = cabinInfo.aiCabinInfos().get(0);
            AiCabinInfo backCabinInfo = cabinInfo.aiCabinInfos().get(1);
            markdown.append("| ").append(cabinInfo.price())
                    .append("| ").append(goCabinInfo.refundChangeRule())
                    .append("| ").append(goCabinInfo.baggageInfo())
                    .append("| ").append(goCabinInfo.remainingSeats())
                    .append("| ").append(goCabinInfo.cabinClass())
                    .append("| ").append(backCabinInfo.refundChangeRule())
                    .append("| ").append(backCabinInfo.baggageInfo())
                    .append("| ").append(backCabinInfo.remainingSeats())
                    .append("| ").append(backCabinInfo.cabinClass())
                    .append("|\n");
        }
        markdown.append("\n");

        return markdown.toString();
    }
}